package com.dc.juc.example._12_future;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;

/**
 * Description: ForkJoinTask Demo
 *
 * @author: gdc
 * @date: 2021/8/18
 * @version 1.0
 */
@Slf4j
public class _3_ForkJoinTask {

    public static void main(String[] args) {
        // 创建一个ForkJoin线程池
        ForkJoinPool forkjoinPool = new ForkJoinPool();

        // 生成一个计算任务，计算1+2+3+4
        Task task = new Task(1, 100);

        // 执行一个任务
        Future<Integer> result = forkjoinPool.submit(task);

        try {
            // 获取任务结果
            log.info("result:{}", result.get());
        } catch (Exception e) {
            log.error("exception", e);
        }
    }


    /**
     * 创建一个任务
     *
     *  继承的RecursiveTask，标识是一个有返回值的任务
     */
    private static class Task extends RecursiveTask<Integer> {
        public static final int threshold = 2;
        /**
         * 开始值
         */
        private int start;
        /**
         * 结束值
         */
        private int end;

        public Task(int start, int end) {
            this.start = start;
            this.end = end;
        }

        @Override
        protected Integer compute() {
            int sum = 0;

            // 如果任务足够小就计算任务
            boolean canCompute = (end - start) <= threshold;
            if (canCompute) {
                for (int i = start; i <= end; i++) {
                    sum += i;
                }
            } else {
                // 如果任务大于阈值，就分裂成两个子任务计算
                int middle = (start + end) / 2;
                Task leftTask = new Task(start, middle);
                Task rightTask = new Task(middle + 1, end);

                // 执行子任务
                leftTask.fork();
                rightTask.fork();

                // 等待任务执行结束合并其结果
                int leftResult = leftTask.join();
                int rightResult = rightTask.join();

                // 合并子任务
                sum = leftResult + rightResult;
            }
            return sum;
        }
    }
}